// CVisUtility.h
// Developed by Yang Yu (yuy@janelia.hhmi.org), Sept 25, 2012
// 

#ifndef __CVISUTILITY_H__
#define __CVISUTILITY_H__

#include <string>
#include <cstring>
#include <cassert>
#include <algorithm>
#include <vector>
#include <limits>

#include <cmath>
#include <ctime>

#include <iostream>
#include <fstream>
#include <sstream>

using namespace std;

#ifndef PI
#define PI 3.14159265358979323846
#endif

#ifndef INF
#define INF 1E9
#endif

#ifndef EPS
#define EPS 1E-9
#endif

#ifndef MAXITERS
#define MAXITERS 100
#endif

#ifndef FUNCONVTOL
#define FUNCONVTOL 1E-4
#endif

typedef float REAL; // precision
// typedef double REAL;

typedef enum { UNKNOWNDT=0, UINT8=1, UINT16=2, FLOAT32=4, FLOAT64=8 } DataType;
typedef enum { UNKNOWNDK, IMAGE, FIELD } DataKind;
typedef enum { UNKNOWNDIMTYPE, D1D, D2D, D3D, D4D, D5D, D6D, D7D, D8D, D9D, DND } DimType;
typedef enum { UNKNOWNAT, AX, AY, AZ, AC, AT } AxisType;
typedef enum { UNKNOWNFF, TIFFIMG, NIFTIIMG, SWC } FileFormat;

typedef enum { NoCompression, PackBits, JPEG, Deflate, LZW } CompressionType;
typedef enum { NOFORMAT, RGB_, GRAYSCALE, PALETTE_RGB, PALETTE_GRAYSCALE, OTHER } PhotometricType;
typedef enum { UNKNOWNCOMPONENTTYPE, UCHAR, CHAR, USHORT, SHORT, UINT, INT, ULONG, LONG, FLOAT, DOUBLE } IOComponentType;
typedef enum { UNKNOWNPIXELTYPE, SCALAR, RGB, RGBA, OFFSET, VECTOR, POINT, COVARIANTVECTOR, SYMMETRICSECONDRANKTENSOR, DIFFUSIONTENSOR3D, COMPLEX, FIXEDARRAY, MATRIX }  IOPixelType;

typedef enum { UNKNOWNERROR, ILLEGALINPUT=-1, UNSUPPORTFILE=-2, ILLEGALCOMMAND=-3 }  ErrorCode;


// 64bit long
#if defined(_MSC_VER) && (_WIN64)
#define LONG64 long long
#else
#define LONG64 long
#endif

//
#define foreach(count, iter) 	\
    for(LONG64 iter=0; iter<count; iter++)

//-------------------
/// basic functions
//-------------------

// max
template <class T> T y_max(T x, T y);

// min
template <class T> T y_min(T x, T y);

// abs
template <class T> T y_abs(T x);

// delete 1d pointer
template <class T> void y_del(T *&p);

// delete 2d pointers
template<class Tdata, class Tidx> void y_del2d(Tdata **&p, Tidx column);

// delete 2 1d pointers
template<class T1, class T2> void y_del2(T1 *&p1, T2 *&p2);

// new 1d pointer
template<class T, class Tidx> void y_new(T *&p, Tidx N);

// sign of 1 variable
template<class T> T y_sign(T x);

// sign of 2 variables
template<class T> T y_sign2v(T a, T b);

// quick sort
template <class Tdata, class Tidx> void quickSort(Tdata *a, Tidx l, Tidx r, Tidx N);

// dist
template<class T> T y_dist(T x1, T y1, T z1, T x2, T y2, T z2);


//------------------------------
/// Image Processing Functions
//------------------------------

template<class Tdata, class Tidx>
class HistogramLUT
{
public:
    
    HistogramLUT(){bins=0; index=0; lut=NULL;}
    ~HistogramLUT(){}

public:
    
    void initLUT(Tdata *p, Tidx sz, Tidx nbins);
    Tidx getIndex(Tdata val);

public:
    
    Tidx bins, index;
    Tdata *lut; // look up table
    REAL minv, maxv;
};

//ANSI C codes from the article "Contrast Limited Adaptive Histogram Equalization"
// by Karel Zuiderveld (karel@cv.ruu.nl) in "Graphics Gems IV", Academic Press, 1994
// modified to templates by Yang Yu (yuy@janelia.hhmi.org) 05/02/2012
template <class Tdata, class Tidx>
int CLAHE2D (Tdata* pImage, Tidx uiXRes, Tidx uiYRes, Tdata Min, Tdata Max,
             Tidx uiNR_OF_GREY, Tidx uiNrX, Tidx uiNrY, Tidx uiNrBins, REAL fCliplimit);


template <class Tidx>
void ClipHistogram2D (Tidx* pulHistogram, Tidx uiNrGreylevels, Tidx ulClipLimit);

template <class Tdata, class Tidx>
void MakeHistogram2D (Tdata* pImage, Tidx uiXRes, Tidx uiSizeX, Tidx uiSizeY,
                      Tidx* &pulHistogram, Tidx uiNrGreylevels, Tdata* pLookupTable);

template <class Tdata, class Tidx>
void MapHistogram2D (Tidx* pulHistogram, Tdata Min, Tdata Max, Tidx uiNrGreylevels, Tidx ulNrOfPixels);

template <class Tdata, class Tidx>
void MakeLut2D (Tdata * pLUT, Tdata Min, Tdata Max, Tidx uiNrBins);

template <class Tdata, class Tidx>
void Interpolate2D (Tdata * pImage, Tidx uiXRes, Tidx * pulMapLU, Tidx * pulMapRU, Tidx * pulMapLB,
                    Tidx * pulMapRB, Tidx uiXSize, Tidx uiYSize, Tdata * pLUT);

// contrast enhancement using CLAHE
template <class Tdata, class Tidx>
void contrastEnhancing(Tdata *&p, Tidx *dims, Tidx datatype, Tidx szblock, Tidx histbins, REAL maxslope);

// gaussian filtering
template <class Tdata, class Tidx> void guassianFiltering(Tdata *&p, Tidx *dims, Tidx *w);

// thresholding
template <class Tdata, class Tidx> void thresholding(Tdata *&p, Tidx *dims);

// rescaling
template <class Tdata, class Tidx> void rescaling(Tdata *&p, Tidx totalplxs, Tdata lv, Tdata rv);

// normalizing
template <class Tdata, class Tidx> void normalizing(Tdata *&p, Tidx totalplxs, Tdata lv, Tdata rv);

// gradient magnitude
template <class Tdata, class Tidx> void gradientMagnitude(Tdata *&p, Tidx *dims);

// surface extracting
template <class Tdata, class Tidx> void extractsurfaces(Tdata *&p, Tidx *dims);

// flip
template <class Tdata, class Tidx> void flip(Tdata *&pOut, Tdata *pIn, Tidx *dims, AxisType atype);

// image copy
template <class Tdata, class Tidx> void imgcopy(Tdata *&pOut, Tdata *pIn, Tidx totalplxs);

// tps basic function
template <class Tdata> Tdata tpsRBF(Tdata r);

// image intersection
template <class Tdata, class Tidx> void imgintersection(Tdata *&pOut, Tdata *p1, Tdata *p2, Tidx totalplxs, Tidx method, Tdata ceilingval);

// implementation
#include "CVisUtility.hpp"

#endif //__CVISUTILITY_H__
